/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" and
 *    "Apache Lucene" must not be used to endorse or promote products
 *    derived from this software without prior written permission. For
 *    written permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    "Apache Lucene", nor may "Apache" appear in their name, without
 *    prior written permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

using System;

namespace DotnetPark.NLucene.Store
{
	/// <summary>
	/// A random-access output stream.
	/// </summary>
	public abstract class OutputStream
	{
		/// <summary>
		/// The maximum buffer size.
		/// </summary>
		public const int BUFFER_SIZE = 1024;

		private byte[] buffer = new byte[BUFFER_SIZE];
		private long bufferStart = 0;			  // position in file of buffer
		private int bufferPosition = 0;		  // position in buffer

		///<summary> OutputStream-like methods @see java.io.InputStream </summary>
		public void WriteByte(byte b) 
		{
			if (bufferPosition >= BUFFER_SIZE)
				Flush();
			buffer[bufferPosition++] = b;
		}

		/// <summary>
		/// [To be supplied.]
		/// </summary>
		/// <param name="b">[To be supplied.]</param>
		/// <param name="length">[To be supplied.]</param>
		public void WriteBytes(byte[] b, int length) 
		{
			for (int i = 0; i < length; i++)
				WriteByte(b[i]);
		}

		/// <summary>
		/// [To be supplied.]
		/// </summary>
		/// <param name="i">[To be supplied.]</param>
		public void WriteInt(int i) 
		{
			WriteByte((byte)(i >> 24));
			WriteByte((byte)(i >> 16));
			WriteByte((byte)(i >>  8));
			WriteByte((byte) i);
		}

		/// <summary>
		/// [To be supplied.]
		/// </summary>
		/// <param name="i">[To be supplied.]</param>
		public void WriteVInt(int i) 
		{
			while ((i & ~0x7F) != 0) 
			{
				WriteByte((byte)((i & 0x7f) | 0x80));
				i >>= 7;
			}
			WriteByte((byte)i);
		}

		/// <summary>
		/// [To be supplied.]
		/// </summary>
		/// <param name="i">[To be supplied.]</param>
		public void WriteLong(long i) 
		{
			WriteInt((int) (i >> 32));
			WriteInt((int) i);
		}

		/// <summary>
		/// [To be supplied.]
		/// </summary>
		/// <param name="i">[To be supplied.]</param>
		public void WriteVLong(long i) 
		{
			while ((i & ~0x7F) != 0) 
			{
				WriteByte((byte)((i & 0x7f) | 0x80));
				i >>= 7;
			}
			WriteByte((byte)i);
		}

		/// <summary>
		/// [To be supplied.]
		/// </summary>
		/// <param name="s">[To be supplied.]</param>
		public void WriteString(String s) 
		{
			int length = s.Length;
			WriteVInt(length);
			WriteChars(s, 0, length);
		}

		/// <summary>
		/// [To be supplied.]
		/// </summary>
		/// <param name="s">[To be supplied.]</param>
		/// <param name="start">[To be supplied.]</param>
		/// <param name="length">[To be supplied.]</param>
		public void WriteChars(String s, int start, int length)
		{
			int end = start + length;
			for (int i = start; i < end; i++) 
			{
				int code = (int)s[i];
				if (code >= 0x01 && code <= 0x7F)
					WriteByte((byte)code);
				else if (((code >= 0x80) && (code <= 0x7FF)) || code == 0) 
				{
					WriteByte((byte)(0xC0 | (code >> 6)));
					WriteByte((byte)(0x80 | (code & 0x3F)));
				} 
				else 
				{
					WriteByte((byte)(0xE0 | (code >> 12)));
					WriteByte((byte)(0x80 | ((code >> 6) & 0x3F)));
					WriteByte((byte)(0x80 | (code & 0x3F)));
				}
			}
		}

		/// <summary>
		/// [To be supplied.]
		/// </summary>
		protected void Flush() 
		{
			FlushBuffer(buffer, bufferPosition);
			bufferStart += bufferPosition;
			bufferPosition = 0;
		}

		/// <summary>
		/// [To be supplied.]
		/// </summary>
		/// <param name="b">[To be supplied.]</param>
		/// <param name="len">[To be supplied.]</param>
		abstract public void FlushBuffer(byte[] b, int len);

		/// <summary>
		/// [To be supplied.]
		/// </summary>
		public virtual void Close() 
		{
			Flush();
		}

		///<summary> RandomAccessFile-like methods @see java.io.RandomAccessFile </summary>
		public long GetFilePointer() 
		{
			return bufferStart + bufferPosition;
		}

		/// <summary>
		/// [To be supplied.]
		/// </summary>
		/// <param name="pos">[To be supplied.]</param>
		public virtual void Seek(long pos)
		{
			Flush();
			bufferStart = pos;
		}

		/// <summary>
		/// [To be supplied.]
		/// </summary>
		abstract public long Length { get; }
	}
}
